package org.xtframe.util;

import java.io.BufferedInputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

import org.jbpm.api.Execution;
import org.jbpm.api.ExecutionService;
import org.jbpm.api.HistoryService;
import org.jbpm.api.JbpmException;
import org.jbpm.api.ManagementService;
import org.jbpm.api.ProcessDefinition;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.ProcessInstance;
import org.jbpm.api.RepositoryService;
import org.jbpm.api.TaskService;
import org.jbpm.api.history.HistoryProcessInstance;
import org.jbpm.api.history.HistoryProcessInstanceQuery;
import org.jbpm.api.model.OpenExecution;
import org.jbpm.api.task.Participation;
import org.jbpm.api.task.Task;
import org.jbpm.pvm.internal.model.ExecutionImpl;
import org.jbpm.pvm.internal.task.OpenTask;
import org.jbpm.pvm.internal.task.TaskImpl;

/**
 * jbpm简单工具类 
 * 
 */
public class JbpmUtil {

	private ProcessEngine processEngine;

	private RepositoryService repositoryService = null;
	private ExecutionService executionService = null;
	private TaskService taskService = null;
	private HistoryService historyService = null;
	private ManagementService managementService = null;

	/**
	 * 实例化相关实体类。
	 * 
	 * @param processEngine
	 */
	private JbpmUtil() {
		processEngine = (ProcessEngine) SpringUtil.getBean("processEngine");
		repositoryService = processEngine.getRepositoryService();
		executionService = processEngine.getExecutionService();
		taskService = processEngine.getTaskService();
		historyService = processEngine.getHistoryService();
		managementService = processEngine.getManagementService();
	}
	
	private static JbpmUtil instance = null;
	
	public static synchronized JbpmUtil getInstance() {
		if(instance == null) instance = new JbpmUtil();
		return instance;
	}

	// ------------------- 实用方法 --------------------

	/**
	 * 部署新流程定义通过路径。
	 * 
	 * @param resourceName
	 * @return
	 */
	public String newDeployDefinitionByPath(String resourceName) {
		return repositoryService.createDeployment()
				.addResourceFromClasspath(resourceName).deploy();
	}

	/**
	 * 部署新流程定义通过zip包
	 * 
	 * @param resourceZipName
	 * @return
	 */
	public String newDeployDefinitionByZip(String resourceZipName) {
		ZipInputStream zis = new ZipInputStream(this.getClass()
				.getResourceAsStream(resourceZipName));
		return repositoryService.createDeployment()
				.addResourcesFromZipInputStream(zis).deploy();
	}
	
	/**
	 * 部署新流程定义通过zip包流
	 * 
	 * @param resourceZipPath
	 * @return
	 */
	public String newDeployDefinitionByZipStream(BufferedInputStream bisZip) {
		ZipInputStream zis = new ZipInputStream(bisZip);
		return repositoryService.createDeployment()
				.addResourcesFromZipInputStream(zis).deploy();
	}

	/**
	 * 部署新流程定义通过url请求。
	 * 
	 * @param urlStr
	 * @return
	 * @throws MalformedURLException
	 *             网络异常
	 */
	public String newDeployDefinitionByUrl(String urlStr)
			throws MalformedURLException {
		URL url = new URL(urlStr);
		return repositoryService.createDeployment().addResourceFromUrl(url)
				.deploy();
	}

	/**
	 * 开始一个流程实例
	 * 
	 * @param id
	 * @param map
	 * @return
	 */
	public ProcessInstance startProcessInstanceById(String processDefinitionId,
			Map<String, ?> variables) {
		return executionService.startProcessInstanceById(processDefinitionId,
				variables);
	}
	
	/**
	 * 根据流程ID判断流程是否结束
	 * @param processInstanceId
	 * @return
	 */
	public boolean isProcessInstanceEnd(String processInstanceId){
		HistoryProcessInstanceQuery histProcQuery = historyService.createHistoryProcessInstanceQuery();
		histProcQuery.processInstanceId(processInstanceId);
		List<HistoryProcessInstance> histProcInstList = histProcQuery.list();
		return HistoryProcessInstance.STATE_ENDED.equals(histProcInstList.get(0).getState());
	}
	
	/**
	 * 根据流程ID获取活动节点的名称
	 * @param executionId
	 * @return
	 */
	public String findActivityName(String executionId){
	    //查找执行中的流程实例，并获取activityName
	    //executionService可以用ProcessEngine.getExecutionService()得到，或使用spring注入
	    ExecutionImpl execution = (ExecutionImpl)executionService.findExecutionById(executionId);
	    if (execution != null)
	      return execution.getActivityName();
	         
	    //如果执行中的流程实例找不到，则认为是此流程实例已结束。
	    //查找历史表中的流程实例，并获取EndActivityName
	    HistoryProcessInstanceQuery histProcQuery = historyService.createHistoryProcessInstanceQuery();
		histProcQuery.processInstanceId(executionId);
	    HistoryProcessInstance historyProcessInstance = histProcQuery.uniqueResult();
	    if (historyProcessInstance == null) 
	    	throw new JbpmException("findActivityName出错，id=" + executionId + "的流程实例不存在！");
	    return historyProcessInstance.getEndActivityName();
	}
	
	/**
	 * 根据流程ID获取流程定义的ID
	 * @param executionId
	 * @return
	 */
	public String findProcessDefinitionId(String executionId){
		HistoryProcessInstanceQuery histProcQuery = historyService.createHistoryProcessInstanceQuery();
		histProcQuery.processInstanceId(executionId);
		HistoryProcessInstance historyProcessInstance = histProcQuery.uniqueResult();
		if (historyProcessInstance == null) 
			throw new JbpmException("findProcessDefinitionId出错，id=" + executionId + "的流程实例不存在！");
		return historyProcessInstance.getProcessDefinitionId();
	}

	/**
	 * 完成任务
	 * 
	 * @param taskId
	 * @param variables
	 */
	public void completeTask(String taskId, Map<String, ?> variables) {
		if (null == variables) {
			taskService.completeTask(taskId);
			return;
		}
		taskService.completeTask(taskId, variables);
	}

	/**
	 * 完成任务
	 * 
	 * @param taskId
	 * @param outcome
	 */
	public void completeTask(String taskId, String outcome) {
		if (null == outcome) {
			taskService.completeTask(taskId);
			return;
		}
		taskService.completeTask(taskId, outcome);
	}

	/**
	 * 获得所有发布的流程
	 * 
	 * @return
	 */
	public List<ProcessDefinition> getAllProcessDefinitionList() {
		return repositoryService.createProcessDefinitionQuery().list();
	}

	/**
	 * 获得所有的流程实例
	 * 
	 * @return
	 */
	public List<ProcessInstance> getAllProcessInstanceList() {
		return executionService.createProcessInstanceQuery().list();
	}

	/**
	 * 根据流程实例executionId与variableName，获取指定的变量值
	 * 
	 * @param executionId
	 * @param variableName
	 * @return
	 */
	public Object getVariableByexecutionId(String executionId,
			String variableName) {
		return executionService.getVariable(executionId, variableName);
	}

	/**
	 * 根据任务taskId与变量名variableName，获取指定变量值
	 * 
	 * @param taskId
	 * @param variableName
	 * @return
	 */
	public Object getVariable(String taskId, String variableName) {
		return taskService.getVariable(taskId, variableName);
	}

	/**
	 * 设置变量
	 * 
	 * @param taskId
	 * @param variables
	 */
	public void setVariables(String taskId, Map<String, ?> variables) {
		taskService.setVariables(taskId, variables);
	}

	/**
	 * 获取指定用户Id的任务
	 * 
	 * @param userId
	 * @return
	 */
	public List<Task> findPersonalTasks(String userId) {
		return taskService.findPersonalTasks(userId);
	}

	/**
	 * 根据任务id获取任务
	 * 
	 * @param taskId
	 * @return
	 */
	public Task getTaskByTaskId(String taskId) {
		return taskService.getTask(taskId);
	}

	/**
	 * 通过主任务，参与会签者，创建子任务
	 * 
	 * @param task
	 * @param users
	 */
	public void createSubTasks(Task task, List<String> users) {

		// OpenTask才有createSubTask方法，Task接口是没有的
		OpenTask oTask = (OpenTask) task;

		// 这个对象非常重要，没有它，通过子任务无法跟主任务获得联系
		Execution execution = executionService.findExecutionById(task
				.getExecutionId());
		// 获得所有的参与者
		for (String userId : users) {
			TaskImpl subTask = (TaskImpl) oTask.createSubTask();
			subTask.setAssignee(userId);
			subTask.setName(task.getName());
			subTask.setFormResourceName(task.getFormResourceName());
			// 这句话是关键 只有设定同样的实例 子任务才能获得主任务设定的变量
			subTask.setExecution((ExecutionImpl) execution);
			taskService.addTaskParticipatingUser(task.getId(), userId,
					Participation.CLIENT);
		}
	}

	/**
	 * @param execution
	 * @return
	 */
	public Task getByOpenExecution(OpenExecution execution) {
		// 获得实例ID
		String pid = execution.getProcessInstance().getId();
		return taskService.createTaskQuery().processInstanceId(pid)
				.activityName(execution.getName()).uniqueResult();
	}

	/**
	 * Saves the given task to persistent storage.
	 * 
	 * @param task
	 * @return
	 */
	public String saveTask(Task task) {
		return taskService.saveTask(task);
	}

	/**
	 * 级联删除流程定义，直接删除该流程定义下的所有实例
	 * 
	 * @param deploymentId
	 *            流程定义id
	 */
	public void deleteDeploymentCascade(String deploymentId) {
		if (deploymentId == null) {
			return;
		}
		repositoryService.deleteDeploymentCascade(deploymentId);
	}

	// getter方法

	public ProcessEngine getProcessEngine() {
		return processEngine;
	}

	public RepositoryService getRepositoryService() {
		return repositoryService;
	}

	public ExecutionService getExecutionService() {
		return executionService;
	}

	public TaskService getTaskService() {
		return taskService;
	}

	public HistoryService getHistoryService() {
		return historyService;
	}

	public ManagementService getManagementService() {
		return managementService;
	}

}
